#include "unixhead.h"

#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

#include <iostream>
using namespace std;

static WFFacilities::WaitGroup waitGroup(1);

void sighandler(int signum)
{
    cout << "wait group done\n";
    (void)signum;
    waitGroup.done();
}

struct SeriesContext
{
    string password;
    protocol::HttpResponse * resp;
};

void redisCallback(WFRedisTask * redisTask);

void httpCallback(WFHttpTask * serverTask);

void process(WFHttpTask * serverTask)
{
    cout << "process function is running\n";
    int state = serverTask->get_state();
    int error = serverTask->get_error();
    cout << "state:" << state << endl;
    switch(state){
    case WFT_STATE_SYS_ERROR:
        fprintf(stderr, "system error: %s\n", strerror(error)); break;
    case WFT_STATE_NOREPLY:
        printf("state is WFT_STATE_NOREPLY\n"); break;
    }

    //接下来是要进行回复
    if(state != WFT_STATE_TOREPLY) {
        printf("error occurs!\n");
        return;
    }

    //获取uri, 解析请求
    auto req = serverTask->get_req();
    auto resp = serverTask->get_resp();
    string method = req->get_method();
    string path = req->get_request_uri();

    if(method == "GET" && path == "/login") {
        //读取服务器本地的文件内容
        // /usr/local/nginx/html/postform.html
        int fd = open("/usr/local/nginx/html/postform.html", O_RDONLY);
        char buff[1024] = {0};
        read(fd, buff, sizeof(buff));

        //将文件内容添加到响应的报文体
        resp->append_output_body(buff, strlen(buff));
        //设置响应报文的首部字段
        resp->add_header_pair("Content-Type", "text/html");
        close(fd);//关闭文件描述符
    } else if(method == "POST" && path == "/login") {
        //获取请求的报文体信息
        const void * body;
        size_t sz;
        req->get_parsed_body(&body, &sz);
        //提取用户名和密码
        string namePasswdKV(static_cast<const char*>(body));
        cout << "user: " << namePasswdKV << endl;

        string nameKV = namePasswdKV.substr(0, namePasswdKV.find("&"));
        string passwordKV = namePasswdKV.substr(namePasswdKV.find("&") + 1);
        string name = nameKV.substr(nameKV.find("=") + 1);
        string password = passwordKV.substr(passwordKV.find("=") + 1);
        cout << "name:" << name << endl
             << "password:" << password << endl;

        //设置共享数据
        auto context = new SeriesContext();
        context->password = password;
        context->resp = serverTask->get_resp();
        series_of(serverTask)->set_context(context);

        //通过Redis任务进行密码的检测
        string url("redis://127.0.0.1:6379");
        auto redisTask = WFTaskFactory::create_redis_task(url, 0, redisCallback);
        auto redisReq = redisTask->get_req();
        redisReq->set_request("HGET", {"student", name});
        //将Redis任务添加到序列中
        series_of(serverTask)->push_back(redisTask);

        //方案一:添加响应的起始行和首部字段
        //方案二:在基本工作对应的回调函数中进行
        serverTask->set_callback(httpCallback);
    }    
}

int main()
{
    signal(SIGINT, sighandler);

    WFHttpServer server(process);

    //start的返回值监听成功返回值为0
    if(0 == server.start(8888)) {
        waitGroup.wait();
        server.stop();   
    } else {
        cout << "server start error!\n";
    }

    return 0;
}


void redisCallback(WFRedisTask * redisTask)
{
    cout << "redisTask callback is running\n";
    auto req = redisTask->get_req();
    auto resp = redisTask->get_resp();
    int state = redisTask->get_state();
    int error = redisTask->get_error();
    protocol::RedisValue value;
    switch(state){
    case WFT_STATE_SYS_ERROR:
        fprintf(stderr, "system error: %s\n", strerror(error)); break;
    case WFT_STATE_DNS_ERROR:
        fprintf(stderr, "dns error: %s\n", gai_strerror(error)); break;
    case WFT_STATE_SUCCESS:
        resp->get_result(value);
        if(value.is_error()) {
            fprintf(stderr, "redis error\n");
            state = WFT_STATE_TASK_ERROR;
        }
        break;
    }

    if(state != WFT_STATE_SUCCESS) {
        printf("error occurs\n");
        return;
    }

    //遍历RedisRequest
    string cmd;
    vector<string> params;
    req->get_command(cmd);
    req->get_params(params);
    cout << "redis command: " << cmd << " ";
    for(auto & param : params) {
        cout << param << " ";
    }
    cout << endl;

    //在RedisTask的回调函数中获取共享数据
    SeriesContext * context = 
        static_cast<SeriesContext*>(series_of(redisTask)->get_context());

    //遍历RedisResponse.RedisValue
    if(value.is_string()) {
        cout << "value is a string, value: " 
             << value.string_value() << endl;
        //与从Http请求之中获取的密码进行对比
        if(value.string_value() == context->password) {
            //登录成功, 生成响应
            context->resp->append_output_body("Login Success!");
        } else {
            //登录失败, 生成响应
            context->resp->append_output_body("Login Failed!");
        }
    } else {
        //登录失败, 生成响应
        context->resp->append_output_body("Login Failed!");
    }
}

void httpCallback(WFHttpTask * serverTask)
{
    cout << "serverTask callback is running" << endl;
    auto resp = serverTask->get_resp();   
    //添加起始行和首部字段
    resp->set_http_version("HTTP/1.1");
    resp->set_status_code("200");
    resp->set_reason_phrase("OK");

    resp->add_header_pair("Server", "Workflow Server");
    resp->add_header_pair("Accept", "*/*");
    resp->add_header_pair("Content-Type", "text/plain");

    //释放context对象
    auto context = static_cast<SeriesContext*>(series_of(serverTask)->get_context());
    delete context;
}
